package cn.lokei.gateway.entity;

import org.springframework.stereotype.Component;

import cn.lokei.gateway.handler.mqtt.MqttHandler;
import cn.lokei.gateway.handler.websocket.MqttMessageWebSocketFrameEncoder;
import cn.lokei.gateway.handler.websocket.WebsocketMqttHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.mqtt.MqttDecoder;
import io.netty.handler.codec.mqtt.MqttEncoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.stream.ChunkedWriteHandler;

public class WSServer extends Server {

  private int port = 1885;

  // 定义一对线程组
  // 主线程组, 用于接受客户端的连接，
  private NioEventLoopGroup mainGroup;
  // 从线程组, 负责IO交互工作
  private NioEventLoopGroup subGroup;

  /**
   * 启动服务
   * 
   * @throws InterruptedException
   */
  public void startup() {
    mainGroup = new NioEventLoopGroup();
    subGroup = new NioEventLoopGroup();
    try {
      ServerBootstrap server = new ServerBootstrap();
      // 绑定两个线程组
      server.group(mainGroup, subGroup)
          // 指定NIO的模式
          .channel(NioServerSocketChannel.class)
          // 子处理器，用于处理workerGroup
          .childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();

              ch.pipeline().addLast("logging", new LoggingHandler("DEBUG"));// 设置log监听器，并且日志级别为debug，方便观察运行流程

              // websocket 基于http协议，所以要有http编解码器 服务端用HttpServerCodec
              pipeline.addLast(new HttpServerCodec());
              // 对写大数据流的支持
              pipeline.addLast(new ChunkedWriteHandler());

              /**
               * 我们通常接收到的是一个http片段，如果要想完整接受一次请求的所有数据，我们需要绑定HttpObjectAggregator，然后我们
               * 就可以收到一个FullHttpRequest-是一个完整的请求信息。
               * 对httpMessage进行聚合，聚合成FullHttpRequest或FullHttpResponse
               * 几乎在netty中的编程，都会使用到此hanler
               */
              pipeline.addLast(new HttpObjectAggregator(1024 * 64));

              // ====================== 以上是用于支持http协议 , 以下是支持httpWebsocket
              // ======================

              /**
               * websocket 服务器处理的协议，用于指定给客户端连接访问的路由 : /ws 本handler会帮你处理一些繁重的复杂的事 会帮你处理握手动作：
               * handshaking（close, ping, pong） ping + pong = 心跳
               * 对于websocket来讲，都是以frames进行传输的，不同的数据类型对应的frames也不同
               */
              // pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));

              // 自定义的handler
              pipeline.addLast(new WebsocketMqttHandler());
              pipeline.addLast(new MqttMessageWebSocketFrameEncoder());
              pipeline.addLast(MqttEncoder.INSTANCE);
              pipeline.addLast(new MqttDecoder());
              pipeline.addLast(new MqttHandler());
            }
          });

      // 启动server，并且设置8088为启动的端口号，同时启动方式为同步
      ChannelFuture future = server.bind(port).sync();
      // 监听关闭的channel，设置位同步方式
      future.channel().closeFuture().sync();
    } catch (Exception e) {
      System.out.println("start exception" + e.toString());
    } finally {
      // 退出线程组
      mainGroup.shutdownGracefully();
      subGroup.shutdownGracefully();
    }
  }
}
